{INCLUDE FILE UABC3 -- IMPLEMENTATION OF UABC}
{Copyright 1983, 1984, Apple Computer, Inc.}

        {TImage-TView-TPaginatedView-TPageView-TPrintManager-THeading-TSelection}



METHODS OF TImage;


    {$S SgABCini}
    FUNCTION  {TImage.}CREATE{(object: TObject; heap: THeap; itsExtent: LRect; itsView: TView): TImage};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TImage(object);

        WITH SELF DO
            BEGIN
            extentLRect := itsExtent;
            view := itsView;
            allowMouseOutside := FALSE;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TImage.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        Field('extentLRect: LRect');
        Field('view: TView');
        Field('allowMouseOutside: BOOLEAN');
        Field('');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S Override}
    FUNCTION {TImage.}CursorAt{(mouseLPt: LPoint): TCursor};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        CursorAt := NoCursor;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S Override}
    PROCEDURE {TImage.}Draw;
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S Override}
    PROCEDURE {TImage.}EachActualPart{(PROCEDURE DoToObject(filteredObj: TObject))};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        SELF.view.panel.window.EachActualPart(DoToObject);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sFilter}
    PROCEDURE {TImage.}EachVirtualPart{(PROCEDURE DoToObject(filteredObj: TObject))};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        SELF.view.panel.window.FilterDispatch(NIL, SELF, DoToObject);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sFilter}
    PROCEDURE {TImage.}FilterAndDo{(actualObj: TObject; PROCEDURE DoToObject(filteredObj: TObject))};
    BEGIN
        {$IFC fTrace}BP(11);{$ENDC}
        SELF.view.panel.window.FilterDispatch(actualObj, SELF, DoToObject);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sCldInit}
    PROCEDURE {TImage.}HaveView{(view: TView)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.view := view;  {fancier subclasses do fancier things here}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION {TImage.}Hit{(mouseLPt: LPoint): BOOLEAN};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        Hit := LRectHasLPt(SELF.extentLRect, mouseLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TImage.}Invalidate;
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        IF thePad <> NIL THEN
            thePad.InvalLRect(SELF.extentLRect);
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S Override}
    FUNCTION {TImage.}LaunchLayoutBox{(view: TView): TImage};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        LaunchLayoutBox := NIL;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TImage.}OffSetBy{(deltaLPt: LPoint)};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
  {$H-} OffsetLRect(SELF.extentLRect, deltaLPt.h, deltaLPt.v); {$H+}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TImage.}OffSetTo{(newTopLeft: LPoint)};
        VAR deltaLPt:   LPoint;
            curTopLeft: LPoint;
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        curTopLeft := SELF.extentLRect.topLeft;
        SetLPt(deltaLPt, newTopLeft.h - curTopLeft.h, newTopLeft.v - curTopLeft.v);
        SELF.OffsetBy(deltaLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TImage.}MouseMove{(mouseLPt: LPoint)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.view.panel <> NIL THEN
            SELF.view.panel.selection.MouseMove(mouseLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TImage.}MousePress{(mouseLPt: LPoint)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.view.panel <> NIL THEN
            SELF.view.panel.selection.MousePress(mouseLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TImage.}MouseRelease;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.view.panel <> NIL THEN
            SELF.view.panel.selection.MouseRelease;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TImage.}MouseTrack{(mPhase: TMousePhase; mouseLPt: LPoint)};
        VAR panel:  TPanel;
            window: TWindow;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        panel := SELF.view.panel;
        IF panel <> NIL THEN
            BEGIN
            IF NOT (panel.selection.canCrossPanels OR SELF.allowMouseOutside) THEN
                LRectHaveLPt(SELF.extentLRect, mouseLPt);
            window := panel.window;
            window.clickPanel := panel;
            END;

        SELF.view.clickLPt := mouseLPt; {e.g., for Set Page Breaks use}
        CASE mPhase OF
            mPress:     SELF.MousePress(mouseLPt);
            mMove:      SELF.MouseMove(mouseLPt);
            mRelease:   BEGIN
                        SELF.MouseMove(mouseLPt);
                        window.Update(TRUE);
                        SELF.MouseRelease;
                        END;
            END;
        window.Update(TRUE);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S Override}
    PROCEDURE {TImage.}ReactToPrinterChange;
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S Override}
    PROCEDURE {TImage.}RecalcExtent;
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TImage.}Resize{(newExtent: LRect)};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        SELF.extentLRect := newExtent;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION {TImage.}SeesSameAs{(image: TImage): BOOLEAN; DEFAULT};    {$}
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        SeesSameAs := image = SELF;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;



METHODS OF TView;


    {$S SgABCini}
    FUNCTION  {TView.}CREATE{(object: TObject; heap: THeap; itsPanel: TPanel; itsExtent: LRect;
                itsPrintManager: TPrintManager; itsDfltMargins: LRect; itsFitPagesPerfectly:BOOLEAN;
                itsRes: Point; isMainView: BOOLEAN): TView};
            VAR screenPad:  TPad;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TView(TImage.CREATE(object, heap, itsExtent, NIL));

        WITH SELF DO
            BEGIN
            view := SELF;
            panel := itsPanel;
            printManager := itsPrintManager;
            res := itsRes;
            clickLPt := itsExtent.topLeft;
            fitPagesPerfectly := itsFitPagesPerfectly;
            {$H-}
            SetPt(scrollPastEnd, 60, 40);
            {$H+}
            END;
        SELF.isMainView := isMainView;
        SELF.isPrintable := (itsPrintManager <> NIL) AND isMainView;

        screenPad := TPad.CREATE(NIL, heap, zeroRect, zeroLRect, screenRes, SELF.res, NIL);
        SELF.screenPad := screenPad;

   {$H-}SetLPt(SELF.stdScroll, (16 * SELF.res.h) DIV screenRes.h, (11 * SELF.res.v) DIV screenRes.v); {$H+}

        IF isMainView THEN
            BEGIN
            itsPanel.HaveView(SELF);
            IF itsPrintmanager <> NIL THEN
                itsPrintManager.Init(SELF, itsDfltMargins);
            SELF.ReactToPrinterChange;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}



    {$S SgABCini}
    PROCEDURE {TView.}Free;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.isMainView THEN
            Free(SELF.printManager);
        Free(SELF.screenPad);
        SUPERSELF.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TView.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        TImage.Fields(Field);
        Field('panel: TPanel');
        Field('clickLPt: LPoint');
        Field('printManager: TPrintManager');
        Field('res: Point');
        Field('screenPad: TPad');
        Field('fitPagesPerfectly: BOOLEAN');
        Field('isPrintable: BOOLEAN');
        Field('isMainView: BOOLEAN');
        Field('stdScroll: LPoint');
        Field('scrollPastEnd: Point');
        Field('');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S SgABCpri}
    PROCEDURE {TView.}AddStripOfPages{(vhs: VHSelect)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.printManager <> NIL THEN
            SELF.printManager.AddStripOfPages(vhs);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


   {$S sCldInit}
    PROCEDURE {TView.}BeInPanel{(panel: TPanel)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.panel := panel;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TView.}CreateUniversalText;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sRes}
    FUNCTION  {TView.}CursorAt{(mouseLPt: LPoint): TCursorNumber};
    BEGIN
        {$IFC fTrace}BP(2);{$ENDC}
        CursorAt := arrowCursor;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgDRWres}
    FUNCTION  {TView.}DoReceive{(selection: TSelection; lPtInView: LPoint): BOOLEAN};
    BEGIN
        {$IFC fTrace}BP(11);{$ENDC}
        DoReceive := FALSE; {Default is to refuse cross-panel drag}
        {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}


    {$S sStartup}
    FUNCTION  {TView.}ForceBreakAt{(vhs: VHSelect; precedingLocation: LONGINT;
                             proposedLocation: LONGINT): LONGINT};
    BEGIN
        {$IFC fTrace}BP(11);{$ENDC}
        ForceBreakAt := proposedLocation;  {default is to accept the proposal; client can override}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sScroll}
    PROCEDURE {TView.}GetStdScroll{(VAR deltaLStd: LPoint)};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        IF NOT SELF.panel.zoomed THEN
            deltaLStd := SELF.stdScroll
        ELSE
            WITH SELF.panel.zoomFactor DO
          {$H-} BEGIN
                deltaLStd.h := LIntOvrInt(LIntMulInt(ORD4(SELF.stdScroll.h), denominator.h), numerator.h);
                deltaLStd.v := LIntOvrInt(LIntMulInt(ORD4(SELF.stdScroll.v), denominator.v), numerator.v);
      {$H+} END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCpri}
    FUNCTION  {TView.}MaxPageToPrint{: LONGINT};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        MaxPageToPrint := SELF.printManager.breaks[v].size * SELF.printManager.breaks[h].size;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sStartup}
    FUNCTION  {TView.}NoSelection{: TSelection};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        NoSelection := TSelection.CREATE(NIL, SELF.Heap, SELF, nothingKind, zeroLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION  {TView.}OKToDrawIn{(lRectInView: LRect): BOOLEAN};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        OKToDrawIn := FALSE;   {The default is to assume the worst, unless the application overrides}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sCldInit}
    PROCEDURE {TView.}ReactToPrinterChange;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.printManager <> NIL THEN
            SELF.printManager.ReactToPrinterChange;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sStartup}
    PROCEDURE {TView.}RedoBreaks;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        IF SELF.printManager <> NIL THEN
            SELF.printManager.RedoBreaks;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TView.}RemapManualBreaks{(
            FUNCTION NewBreakLocation(vhs: VHSelect; oldBreak: LONGINT): LONGINT)};
        VAR printManager:   TPrintManager;
            oldLoc:	    LONGINT;
            newLoc:	    LONGINT;
            oldIndex:	    LONGINT;
            vhs:	    VHSelect;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        printManager := SELF.printManager;
        IF printManager <> NIL THEN
            BEGIN
            printManager.ClearPageBreaks(TRUE);
            FOR vhs := v TO h DO
                FOR oldIndex := 1 TO printManager.breaks[vhs].size - 1 DO
                BEGIN
                oldLoc := TpLONGINT(printManager.breaks[vhs].At(oldIndex))^;
                newLoc := - NewBreakLocation(vhs, ABS(oldLoc));
                printManager.breaks[vhs].PutAt(oldIndex, @newLoc);
                END;
            SELF.RedoBreaks;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sCldInit}
    PROCEDURE {TView.}Resize{(newExtent: LRect)};
        VAR s:		    TListScanner;
            pageBreak:	    LONGINT;
            vhs:	    VHSelect;
            oldLimit:	    LONGINT;
            newLimit:	    LONGINT;
            breakIndex:	    INTEGER;
            breakArray:	    TArray;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        IF NOT (SELF.isMainView) OR NOT(SELF.isPrintable) THEN
            SUPERSELF.Resize(newExtent)
        ELSE
            IF NOT EqualLRect(SELF.extentLRect, newExtent) THEN
                BEGIN
                FOR vhs := v TO h DO
                    BEGIN
                    oldLimit := SELF.extentLRect.botRight.vh[orthogonal[vhs]];
                    newLimit := newExtent.botRight.vh[orthogonal[vhs]];

                    breakIndex := 1;
                    breakArray := SELF.printManager.breaks[vhs];

                    WHILE breakIndex <= breakArray.size DO
                        BEGIN
                        pageBreak := TpLONGINT(breakArray.At(breakIndex))^;
                        IF pageBreak = oldLimit THEN
                            BEGIN
                            {reset the end-of-view pagebreak to new limit}
                            pageBreak := newLimit;
                            breakArray.PutAt(breakIndex, @pageBreak);
                            END
                        ELSE
                        IF ABS(pageBreak) >= newLimit THEN
                            {discard other now-too-big pagebreaks}
                            BEGIN
                            breakArray.DelAt(breakIndex);
                            breakIndex := breakIndex - 1;
                            END;
                        breakIndex := breakIndex + 1;
                        {ELSE pagebreak still valid; do nothing}
                        END;
                    END;
                SELF.extentLRect := newExtent;
                SELF.panel.Rescroll;
                END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    PROCEDURE {TView.}SetFunctionValue{(keyword: S255; VAR itsValue: S255)};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        StrUpperCased(@keyword);

        IF keyword = varPage THEN  {+SW+}
            LIntToStr(theMarginPad.pageNumber, @itsValue)
        ELSE
        IF keyword = varTitle THEN {+SW+}
            SELF.panel.window.GetTitle(itsValue)

       {ELSE
        IF keyword = ....   *** this is where to add more predefined functions ***}

        ELSE {didn't parse}
            itsValue := keyword;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    PROCEDURE {TView.}SetMinViewSize{(VAR minLRect: LRect)};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        minLRect := SELF.extentLRect; {client may override this to inspect his view for other ideas}
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;
{$S SgABCres}



METHODS OF TPaginatedView;


{$S SgABCpri}
    FUNCTION {TPaginatedView.}CREATE{(object: TObject; heap: THeap; itsUnpaginatedView: TView)
                                     : TPaginatedView};
        VAR viewExtent:	        LRect;
            pgsPerRowStrip:     INTEGER;
            pgsPerColStrip:     INTEGER;
            pageWidth:	        LONGINT;
            pageHeight:	        LONGINT;
            printerMetrics:     TPrinterMetrics;
            pageList:	        TList;
            rowStrip:	        INTEGER;
            colStrip:	        INTEGER;
            pageOrigin:	        LPoint;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        printerMetrics := itsUnpaginatedView.printManager.printerMetrics;
        pgsPerRowStrip := itsUnpaginatedView.printManager.breaks[v].size;
        pgsPerColStrip := itsUnpaginatedView.printManager.breaks[h].size;

        WITH printerMetrics, paperRect DO
            BEGIN
            pageWidth := LIntOvrInt(LIntMulInt(ORD4(right - left), itsUnpaginatedView.res.h),
                                    printerMetrics.res.h);
            pageHeight:= LIntOvrInt(LIntMulInt(ORD4(bottom - top), itsUnpaginatedView.res.v),
                                    printerMetrics.res.v);
            END;

        SetLRect(viewExtent, 0, 0, pgsPerRowStrip * ORD4(pageWidth), pgsPerColStrip * ORD4(pageHeight));

        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TPaginatedView(TView.CREATE(object, heap, itsUnpaginatedView.panel, viewExtent,
                                       itsUnpaginatedView.printManager, zeroLRect, FALSE,
                                       itsUnpaginatedView.res, FALSE));

        WITH SELF DO
            BEGIN
            unpaginatedView := itsUnpaginatedView;
            pageSize[h] := pageWidth;
            pageSize[v] := pageHeight;
            workingInMargins := FALSE;
            END;

       {$IFC fTrace}EP;{$ENDC}
    END;


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TPaginatedView.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        TView.Fields(Field);
        Field('unPaginatedView: TView');
        Field('pageSize: ARRAY[0..1] OF LONGINT');
        Field('workingInMargins: BOOLEAN');
        Field('');
    END;
    {$S SgABCcld}
    {$ENDC}


    {$S SgABCpri}
    PROCEDURE {TPaginatedView.}AddStripOfPages{(vhs: VHSelect)};
        VAR panel:  TPanel;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        panel := SELF.panel;
        panel.Preview(mPrvwOff); {get back to main-view metrics in the panes}
       {Don't refer to SELF after this, since Preview has deallocated me}
        panel.view.printManager.AddStripOfPages(vhs);
        panel.Preview(mPrvwMargins); {creates fresh paginated view with correct info}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCpri}
    PROCEDURE {TPaginatedView.}AdornPageOnScreen;  {+SW+} {now using CONSTs to tune layout of pg numbers}
        CONST
{$IFC LibraryVersion <= 20}
                lrOffset = 10;
                topOffset = 22;
                bottomOffset = 9;

                lrOutset = 6;
                topOutset = 4;
                bottomOutset = 2;
{$ELSEC}
                lrOffset = 10;
                topOffset = 22;
                bottomOffset = 9;

                lrOutset = 6;
                topOutset = 1;  {+SW+}
                bottomOutset = 1;
{$ENDC}
        VAR pgNum:	    S255;
            r:		    Rect;
            tempRect:	    Rect;
            paperRect:	    Rect;
            contentRect:    Rect;
            pat:	    pattern;
{$IFC LibraryVersion <= 20}
            fInfo:	    TFInfo;
{$ELSEC}
            fInfo:	    FontInfo;
{$ENDC}
            numberLength:   INTEGER;
            printManager:   TPrintManager;

        PROCEDURE DistinguishScreenFeedback(theString: S255; h, v: INTEGER);
                VAR box: Rect;
            BEGIN
            WITH box, fInfo DO
                BEGIN
                left := h - lrOutset;
                right := h + StringWidth(theString) + lrOutset;
                top := v - ascent - leading - topOutset;
                bottom := v + descent + leading + bottomOutset;
                END;
            FillRoundRect(box, 10, 10, white);{*** These constants won't stand up under zooming! ***}
            MoveTo(h, v);
            DrawString(theString);
            InvertRoundRect(box, 10, 10);
            END;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        printManager := SELF.unpaginatedView.printManager;

        IF focusArea <> theMarginPad THEN   {need to refocus onto the exterior...}
            theMarginPad.Focus;

        {frame the overall page}
        penNormal;
        penMode(patOr);
        penSize(3,2);
        FrameLRect(printManager.paperLRect);

        {draw a very light-gray pattern everywhere in the margins}
        theMarginPad.LRectToRect(printManager.paperLRect, paperRect);
        RectRgn(padRgn, paperRect);
        theMarginPad.LRectToRect(printManager.contentLRect, contentRect);
        RectRgn(scrRgn1ForDrawHdgs, contentRect);
        DiffRgn(padRgn, scrRgn1ForDrawHdgs, scrRgn1ForDrawHdgs);
        PenMode(patOr);
        theMarginPad.LPatToPat(marginPattern, pat);
        PenPat(pat);
        PaintRgn(scrRgn1ForDrawHdgs);

        IF NOT EqualRect(theBodyPad.nonNullBody, theBodyPad.innerRect) THEN
            BEGIN
            RectRgn(scrRgn1ForDrawHdgs, theBodyPad.innerRect);
            RectRgn(scrRgn2ForDrawHdgs, theBodyPad.nonNullBody);
            DiffRgn(scrRgn1ForDrawHdgs, scrRgn2ForDrawHdgs, scrRgn1ForDrawHdgs);

            {Both theBodyPad.innerRect & theBodyPad.nonNullBody are expressed in (0,0)-origined
                window coordinates; since we are focused on theMarginPad now, must offset the
                rgn by its origin.}
            WITH theMarginPad.origin DO
                {$H-}
                OffsetRgn(scrRgn1ForDrawHdgs, h, v);
                {$H+}

            thePad.SetPen(limboPen);
            PaintRgn(scrRgn1ForDrawHdgs);
            END;

      {Frame the content rectangle--normally directly abuts the margin}
        penNormal;
        penMode(patOr);
        FrameRect(contentRect);

      {draw page numbers in corners}
        IntToStr(theMarginPad.pageNumber, @pgNum);
        SetQDTypeStyle(cornerNumberStyle);
        numberLength := StringWidth(pgNum);
        r := paperRect;
        GetFontInfo(fInfo);
        DistinguishScreenFeedback(pgNum, r.left + lrOffset, r.top + topOffset);
        DistinguishScreenFeedback(pgNum, r.right - numberLength - lrOffset, r.top + topOffset);
        DistinguishScreenFeedback(pgNum, r.right - numberLength - lrOffset, r.bottom - bottomOffset);
        DistinguishScreenFeedback(pgNum, r.left + lrOffset, r.bottom - bottomOffset);

        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}



   {$S SgABCpri}
   FUNCTION  {TPaginatedView.}CursorAt{(mouseLPt: LPoint): TCursorNumber};
                                            {later deal with cursor for margins}
        VAR unPagLPt: LPoint;
    BEGIN
       {$IFC fTrace}BP(9);{$ENDC}
       SELF.DepagifyLPoint(mouseLPt, unPagLPt);
       CursorAt := SELF.unpaginatedView.CursorAt(unPagLPt);
       {$IFC fTrace}EP;{$ENDC}
    END;


  PROCEDURE {TPaginatedView.}DepagifyLPoint{(pagLPt: LPoint; VAR unPagLPt: LPoint)};
   {Given a point in the paginated view, determine the nearest corresponding point in the unpaginated view}

        VAR printManager:   TPrintManager;
            meatLRect:	    LRect;      {the portion of the page that displays a part of the main view}
            vhs:	    VHSelect;
            breakArray:	    TArray {OF LONGINT};
            strip:	    INTEGER;    {the ordinal number of the strip containing the page}
            breakLocation:  LONGINT;    {the coordinate of the start of the page}
            pageBreak:	    LONGINT; {the page break at the beginning of the page}
            nextBreak:	    LONGINT; {the page break at the end of the page}
            pageOrigin:	    LPoint;     {the top left corner of the page, in the paginated view}
            strips:	    Point;      {the strip numbers in each direction, stored as a Point}
            lOffsetPt:	    LPoint;     {the top left corner of the meat rect of the page, in the main view}

    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        LRectHaveLPt(SELF.extentLRect, pagLPt);

        printManager := SELF.unpaginatedView.printManager;
        meatLRect := printManager.contentLRect;

        FOR vhs := v TO h DO
            BEGIN
            breakArray := printManager.breaks[orthogonal[vhs]];

          {compute strip number}
            strip := Min(LIntDivLInt(pagLPt.vh[vhs], SELF.pageSize[vhs]) + 1, breakArray.size);

          {compute breakLocation, being the location in the main view of the top-leftmost
                    content point of the page in which our boy was found}
            IF strip = 1 THEN
                breakLocation := 0
            ELSE
                BEGIN
                pageBreak := TpLONGINT(breakArray.At(strip - 1))^;
                breakLocation := ABS(pageBreak);
                END;

          {recompute end of meatLRect (limbo boundary)}
            nextBreak := TpLONGINT(breakArray.At(strip))^;
            meatLRect.botRight.vh[vhs] := meatLRect.topLeft.vh[vhs] + ABS(nextBreak) - breakLocation;

          {compute pageOrigin -- the location in the paginated view of the topleft corner of this page}
            pageOrigin.vh[vhs] := LIntMulInt(SELF.pageSize[vhs], strip - 1);

          {stuff strip and breakLocation into points for future reference}
            strips.vh[vhs] := strip;
            lOffsetPt.vh[vhs] := breakLocation;
            END;

      {project the point into the (0,0)-origined space that the printManager rectangles are in}
        LPtMinusLPt(pagLPt, pageOrigin, pagLPt);
        LRectHaveLPt(meatLRect, pagLPt);  {force it to meat rectangle}
        LPtMinusLPt(pagLPt, meatLRect.topLeft, pagLPt); {get offset from inner corner}
        LPtPlusLPt(pagLPt, lOffsetPt, unPagLPt);  {project onto main view}
        {$IFC fTrace}EP;{$ENDC}
    END;


    PROCEDURE {TPaginatedView.}DoOnPages{(focusOnInterior: BOOLEAN; PROCEDURE DoOnAPage))};
        VAR pgsPerStrip:    INTEGER;  {pages per row-strip if pageRiseDirection = h}
            firstRowStrip:  INTEGER;
            firstColStrip:  INTEGER;
            lastRowStrip:   INTEGER;
            lastColStrip:   INTEGER;
            row:	    INTEGER;
            column:	    INTEGER;
            pageNumber:	    LONGINT;
            lOrigin:	    LPoint;
            origin:	    Point;
            anLRect:	    LRect;
            incomingPane:   TPane;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
            incomingPane := TPane(thePad);
            anLRect := thePad.visLRect;
            IF SectLRect(anLRect, SELF.extentLRect, anLRect) THEN
                {thanks for the lovely intersection};

            IF EqualLRect(anLRect, zeroLRect) THEN
                BEGIN
                {$IFC fTrace}EP;{$ENDC}
                EXIT(DoOnPages);
                END;

            pgsPerStrip := SELF.printManager.breaks[
                                orthogonal[SELF.printManager.pageRiseDirection]].size;


            WITH anLRect, SELF DO
                BEGIN
         {$H-}  firstRowStrip := LIntDivLInt(topLeft.v, pageSize[v]) + 1;
                firstColStrip := LIntDivLInt(topLeft.h, pageSize[h]) + 1;
                lastRowStrip :=	 MIN(LIntDivLInt(botRight.v, pageSize[v]) + 1,
                         SELF.printManager.breaks[h].size);
                lastColStrip :=	 MIN(LIntDivLInt(botRight.h, pageSize[h]) + 1,
                         SELF.printManager.breaks[v].size);
         {$H+}  END;

            PushFocus;
            IF (theMarginPad.view <> SELF.unpaginatedView) OR (theMarginPad.port = printerPseudoPort) THEN
               theMarginPad.Rework(SELF.unpaginatedView, zeroPt, screenRes, 1,
                         SELF.panel.zoomFactor, POINTER(SELF.panel.window.wmgrId));

            FOR row := firstRowStrip TO lastRowStrip DO
                FOR column := firstColStrip to lastColStrip DO
                    BEGIN
                    IF SELF.printManager.pageRiseDirection = h THEN
                        pageNumber := (row - 1) * pgsPerStrip + column
                    ELSE
                        pageNumber := (column - 1) * pgsPerStrip + row;
                    SetLPt(lOrigin,
                            LIntMulInt(SELF.pageSize[h], column - 1)  - incomingPane.scrollOffset.h,
                            LIntMulInt(SELF.pageSize[v], row - 1)     - incomingPane.scrollOffset.v);
                    SELF.screenPad.LPtToPt(lOrigin, origin);

                    theMarginPad.SetForPage(pageNumber, origin);

                    theMarginPad.ClipFurtherTo(incomingPane.innerRect); {clip page down to pane}
                    theBodyPad.ClipFurtherTo(incomingPane.innerRect);   {ditto page body}
                    IF focusOnInterior THEN
                        theBodyPad.Focus
                    ELSE
                        theMarginPad.Focus;

                    DoOnAPage;

                    END;
            PopFocus;
        {$IFC fTrace}EP;{$ENDC}
    END;


    PROCEDURE {TPaginatedView.}Draw;
        PROCEDURE DrawPageOnScreen;
        BEGIN
            SELF.printManager.DrawPage;
            SELF.AdornPageOnScreen;
        END;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        SELF.DoOnPages(FALSE, DrawPageOnScreen);
        {$IFC fTrace}EP;{$ENDC}
    END;


    PROCEDURE {TPaginatedView.}MouseTrack{(mPhase: TPhase; mouseLPt: LPoint)};
        VAR unPagLPt: LPoint;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        SELF.DepagifyLPoint(mouseLPt, unPagLPt);
        SELF.unpaginatedView.MouseTrack(mphase, unPagLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    PROCEDURE {TPaginatedView.}PagifyLPoint{(unPagLPt: LPoint; VAR pagLPt: LPoint)};
        VAR pageBreak:  LONGINT;
            strip:      Point;
            vhs:        VHSelect;
            pageNumber: LONGINT;
            orthoVhs:   VHSelect;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        pageNumber := SELF.printManager.PageWith(unPagLPt, strip);
        FOR vhs := v TO h DO
            BEGIN
            orthoVhs := orthogonal[vhs];
            IF (strip.vh[orthoVhs] < 1) OR (strip.vh[orthoVhs] > SELF.printManager.breaks[orthoVhs].Size) THEN
                ABCBreak('PagifyLPt: strip=', strip.vh[orthoVHs])      {only for short-term debugging}
            ELSE
            IF strip.vh[orthoVhs] = 1 THEN
                pagLPt.vh[vhs] := unPagLPt.vh[vhs] + SELF.printManager.contentLRect.topLeft.vh[vhs]
            ELSE
                BEGIN
                pageBreak := TpLONGINT(SELF.printManager.breaks[orthoVhs].At(strip.vh[orthoVhs] - 1))^;
                pagLPt.vh[vhs] := unPagLPt.vh[vhs] + SELF.printManager.contentLRect.topLeft.vh[vhs]
                         + LIntMulInt(SELF.pageSize[vhs], strip.vh[orthoVhs] - 1) - ABS(pageBreak);
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;



   {$S SgABCpri}
    PROCEDURE {TPaginatedView.}ReactToPrinterChange;
        VAR panel:  TPanel;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        panel := SELF.panel;
        panel.Preview(mPrvwOff); {get back to main-view metrics in the panes}
       {Don't refer to SELF after this, since Preview has deallocated me}
        panel.view.ReactToPrinterChange;
        panel.Preview(mPrvwMargins); {creates fresh paginated view with correct info}
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    PROCEDURE {TPaginatedView.}RedoBreaks;
        VAR panel: TPanel;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        panel := SELF.panel;
        panel.Preview(mPrvwOff); {get back to main-view metrics in the panes}
       {Don't refer to SELF after this, since Preview has deallocated me}
        panel.view.ReDoBreaks;
        panel.Preview(mPrvwMargins); {creates fresh paginated view with correct info}
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;
{$S SgABCres}


METHODS OF TPageView;

{$S sCldInit}
    FUNCTION  {TPageView.}CREATE{(object: TObject; heap: THeap; itsPrintManager: TPrintManager): TPageView};
        VAR view:       TView;
    BEGIN
       {$IFC fTrace}BP(9);{$ENDC}
        view := itsPrintManager.view;
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TPageView(TView.CREATE(object, heap, view.panel, itsPrintManager.paperLRect,
                             itsPrintManager, zeroLRect, FALSE, view.res, FALSE));
       {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}


{$S SgABCpri}
    PROCEDURE  {TPageView.}Draw;
        VAR s:	        TListScanner;
            heading:    THeading;
            pageNumber: LONGINT;
            outerFrame: LRect;
            headings:   TList;
            editing:    BOOLEAN;
    BEGIN
       {$IFC fTrace}BP(9);{$ENDC}
        PenNormal;
        IF SELF.printManager.frameBody THEN {body should be framed...}
            IF amPrinting THEN
                FrameLRect(SELF.printManager.contentLRect);

        editing := (SELF.printManager.layoutDialogBox <> NIL) AND
            (SELF.printManager.view.panel.window.dialogBox = SELF.printManager.layoutDialogBox);

        headings := SELF.printManager.headings;
        IF headings <> NIL THEN
            BEGIN
            pageNumber := theMarginPad.pageNumber;
            s := headings.Scanner;   {tell each Heading to draw itself}
            WHILE s.Scan(heading) DO
                IF heading.ShouldDraw(pageNumber)  THEN
                    BEGIN
                    IF NOT editing THEN
                        BEGIN
                        heading.AdjustForPage(pageNumber, FALSE);       {client changes contents/extent}
                        heading.LocateOnPage(FALSE);		        {...then we adjust to page}
                        END;
                    heading.Draw;
                    END;
            END;
       {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}


{$S SgABCini}
END;
{$S SgABCres}


{$S SgABCini}
METHODS OF TPrintManager;


    FUNCTION  {TPrintManager.}CREATE{(object: TObject; heap: THeap): TPrintManager};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TPrintManager(object);
        {$IFC fTrace}EP;{$ENDC}
    END;


    PROCEDURE  {TPrintManager.}Init{(itsMainView: TView; itsDfltMargins: LRect)};
        VAR paperLRect: LRect;
            l:	        TArray;
            vhs:        VHSelect;
            pageView:   TView;
            pageBreak:  LONGINT;
            newList:    TList;
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        newList := TList.CREATE(NIL, itsMainView.Heap, 0);  {the Headings}

        WITH SELF  DO
            BEGIN
            view := itsMainView;
            headings := newList;
            pageRiseDirection := h;
            frameBody := FALSE;
            layoutDialogBox := NIL;
            canEditPages := FALSE;     {subclass may make true}
            END;

        FOR vhs := v TO h DO
            BEGIN
            l := TArray.CREATE(NIL, itsMainView.Heap, 1, SIZEOF(LONGINT));
            pageBreak := itsMainView.extentLRect.botRight.vh[orthogonal[vhs]];
            l.InsFirst(@pageBreak);

            SELF.breaks[vhs] := l;
            END;

        WITH itsDfltMargins DO
            BEGIN {$H-}
            left := ABS(left);
            top := ABS(top);
            right := - ABS(right);
            bottom := - ABS(bottom);
            END; {$H+}
        SELF.pageMargins := itsDfltMargins;

        pageView := SELF.NewPageView(NIL);
        SELF.pageView := pageView;

        SELF.SetDfltHeadings;	     {NB: TView.CREATE will, after calling me, call ReactToPrinterChange;
                                          until that's done, things are not necessarily in synch}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCini}
    PROCEDURE {TPrintManager.}Free;
        VAR vhs:    VHSelect;
    BEGIN
        {$IFC fTrace}BP(2);{$ENDC}
        FOR vhs := v TO h DO
            IF SELF.breaks[vhs] <> NIL THEN
                SELF.breaks[vhs].Free;
        Free(SELF.pageView);
        SUPERSELF.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TPrintManager.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        Field('view: TView');
        Field('pageView: TPageView');
        Field('breaks: ARRAY[0..1] OF TArray');
        Field('pageMargins: LRect');
        Field('headings: TList');
        Field('canEditPages: BOOLEAN');
        Field('layoutDialogBox: TDialogBox');
        Field('frameBody: BOOLEAN');
        Field('paperLRect: LRect');
        Field('printableLRect: LRect');	     {safeLRect out}
        Field('contentLRect: LRect');
        Field(CONCAT('printerMetrics: RECORD paperRect: Rect; printRect: Rect; ',
                      'res: Point; reserve: ARRAY[0..7] OF Byte END'));
        Field('pageRiseDirection: BOOLEAN');
        Field('');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S SgABCpri}
    PROCEDURE {TPrintManager.}AddStripOfPages{(vhs: VHSelect)};
        VAR newExtentLRect: LRect;
            adjustment:	    LONGINT;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
            WITH SELF.contentLRect DO  {cd save a mote by flipping vhs just before this}
                adjustment := botRight.vh[orthogonal[vhs]] - topLeft.vh[orthogonal[vhs]];
            WITH SELF.view.extentLRect DO
                IF vhs = v THEN
      {$H-}	    SetLRect(newExtentLRect, left, top, right + adjustment, bottom)
                ELSE
                    SetLRect(newExtentLRect, left, top, right, bottom + adjustment); {$H+}
            SELF.view.Resize(newExtentLRect);
            SELF.RedoBreaks;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCpri}
    PROCEDURE {TPrintManager.}ChangeMargins{(margins: LRect)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        WITH margins DO
            BEGIN {$H-}
            left := ABS(left);
            top := ABS(top);
            right := - ABS(right);
            bottom := - ABS(bottom);
            END; {$H+}
        SELF.pageMargins := margins;
        SELF.view.panel.currentView.ReactToPrinterChange;
        SELF.view.panel.Invalidate;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sCldInit}
    PROCEDURE {TPrintManager.}ClearPageBreaks{(automatic: BOOLEAN)};
         VAR s:	        TListScanner;
             break:     LONGINT;
             vhs:       VHSelect;
             endOfView: LONGINT;
             breakIndex:    INTEGER;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        { Clears all page breaks of the specified kind EXCEPT for the one marking the end of the view }
            FOR vhs := v TO h DO
                BEGIN
                endOfView := SELF.view.extentLRect.botRight.vh[orthogonal[vhs]];
                breakIndex := 1;
                WHILE breakIndex < SELF.breaks[vhs].size DO
                    BEGIN
                    break := TpLONGINT(SELF.breaks[vhs].At(breakIndex))^;
                    IF (break >= 0) = automatic THEN
                        IF ABS(break) < endOfView THEN
                            BEGIN
                            SELF.breaks[vhs].DelAt(breakIndex);
                            breakIndex := breakIndex - 1;
                            END;
                    breakIndex := breakIndex + 1;
                    END;
                END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    PROCEDURE {TPrintManager.}DrawBreaks{(manualOnly: BOOLEAN)};
        VAR wLPt1:	    LPoint;
            wLPt2:	    LPoint;
            vhs:	    VHSelect;
            dir:	    VHSelect;
            viewEnd:	    LONGINT;
            visEnd:	    LONGINT;
            widthAdjust:    INTEGER;
            showing:	    BOOLEAN;
            limit:	    LONGINT;
            pageBreak:	    LONGINT;
            breakIndex:	    INTEGER;
            finished:	    BOOLEAN;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
            thePad.DistToLDist(autoBreakPen.pnSize, wLPt1);
            thePad.DistToLDist(manualBreakPen.pnSize, wLPt2);
            IF NOT amPrinting THEN
                FOR vhs := v TO h DO
                    BEGIN
                  {Inhibit display of breaks to the top/left of the pane}
                    dir := orthogonal[vhs];
                    viewEnd := SELF.view.extentLRect.botRight.vh[dir];
                    visEnd := thePad.visLRect.botRight.vh[dir];
                    widthAdjust := Max(wLPt1.vh[dir], wLPt2.vh[dir]) + 1;  {add 1 in case of roundoff
                                                                            problems}

                    showing := FALSE;
                    limit := thePad.visLRect.topLeft.vh[dir];

                    breakIndex := 1;
                    finished := FALSE;
                    WHILE (breakIndex <= SELF.breaks[vhs].size) AND NOT finished DO
                        BEGIN
                        pageBreak := TpLONGINT(SELF.breaks[vhs].At(breakIndex))^;
                        IF ABS(pageBreak) >= limit THEN
                            BEGIN
                            IF NOT showing THEN	   {Start displaying breaks; reset limit to where we'll stop}
                                limit := Min(viewEnd, visEnd + widthAdjust);
                            showing := ABS(pageBreak) < limit;
                            IF NOT showing THEN	  {Stop displaying breaks}
                                finished := TRUE;
                            END;
                        IF showing THEN
                            IF NOT ( (pageBreak >= 0) AND manualOnly) THEN
                                SELF.DrawOneBreak(pageBreak, vhs);
                        breakIndex := breakIndex + 1;
                        END;
                    END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    PROCEDURE {TPrintManager.}DrawOneBreak{(pageBreak: LONGINT; vhs: vhSelect)};
        VAR lPt1:   LPoint;
            lPt2:   LPoint;
            pt:	    Point;
            wPt:    Point; {width of line}
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}

        IF pageBreak >= 0 THEN
            thePad.SetPen(autoBreakPen)
        ELSE
            thePad.SetPen(manualBreakPen);

        lPt1 := zeroLPt;
        lPt2 := SELF.view.extentLRect.botRight;
        lPt1.vh[orthogonal[vhs]] := ABS(pageBreak);
        lPt2.vh[orthogonal[vhs]] := ABS(pageBreak);

        wPt := thePort^.pnSize;
        wPt.vh[vhs] := 0;

        thePad.LPtToPt(lPt1, pt);
        MoveTo(pt.h - wPt.h, pt.v - wPt.v); {wPt adjustment to hang line off top/left, not bot/right}

        thePad.LPtToPt(lPt2, pt);
        LineTo(pt.h - wPt.h, pt.v - wPt.v); {wPt adjustment to hang line off top/left, not bot/right}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCpri}
    PROCEDURE {TPrintManager.}DrawPage;
        VAR    heading:	        THeading;
                contentRect:    Rect;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF (amPrinting) AND (SELF.frameBody) THEN {client wants frame drawn on printed page}
            BEGIN
            theMarginPad.LRectToRect(SELF.contentLRect, contentRect);
            PenNormal;
            PenSize(3,2);
            PenMode(patOr);
            InsetRect(contentRect, -1, -1);
            FrameRect(contentRect);
            END;

        SELF.pageView.Draw;  {will draw headings and possibly frame body}

        theBodyPad.Focus;
        SELF.view.Draw;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


   {$S SgABCpri}
    PROCEDURE {TPrintManager.}EnterPageEditting;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCpri}
    PROCEDURE {TPrintManager.}GetPageLimits{(pageNumber: LONGINT; VAR viewLRect: LRect)};
    { NB:
          The default is that page numbers go up from left-to-right, as illustrated by:

             |--------|--------|--------|
             | page 1 | page 2 | page 3 |
             |--------|--------|--------|
             | page 4 | page 5 | page 6 |
             |--------|--------|--------|

          This is what is obtained by leaving TPrintManager.pageRiseDirection
           at its default value of 'h'; to get the transpose, set pageRiseDirection 'v'
      }

        VAR
            totalStrips:        INTEGER;  {if pageRiseDirection is h, this is the total number of column
                                            strips}
            pageRiseDirection:  VHSelect;
            orthoDirection:     VHSelect;
            strips:	        Point;
            vhs:	        VHSelect;
            breakArray:	        TArray {OF LONGINT};
            strip:	        INTEGER;
            nextLocation:       LONGINT;
            pageBreak:	        LONGINT;
     BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        pageRiseDirection := SELF.pageRiseDirection;
        orthoDirection := orthogonal[pageRiseDirection];
        totalStrips := SELF.breaks[orthoDirection].size;

        strips.vh[orthoDirection] := ((pageNumber - 1) DIV totalStrips) + 1;
        strips.vh[pageRiseDirection] := pageNumber - ((strips.vh[orthoDirection] - 1) * totalStrips);

        FOR vhs := v TO h DO
            BEGIN
            breakArray := SELF.breaks[orthogonal[vhs]];
            strip := strips.vh[vhs];

            IF strip = 1 THEN
                nextLocation := 0
            ELSE
                BEGIN
                pageBreak := TpLONGINT(breakArray.At(strip - 1))^;
                nextLocation := ABS(pageBreak);
                END;

            viewLRect.topLeft.vh[vhs] := nextLocation;
            pageBreak := TpLONGINT(breakArray.At(strip))^;
            viewLRect.botRight.vh[vhs] := ABS(pageBreak);
            END;
        {$IFC fTrace}EP;{$ENDC}
     END;
    {$S SgABCres}


    FUNCTION  {TPrintManager.}NewPageView{(object: TObject): NewPageView};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        NewPageView := TPageView.CREATE(object, SELF.Heap, SELF);
        {$IFC fTrace}EP;{$ENDC}
    END;


    FUNCTION  {TPrintManager.}NewPaginatedView{(object: TObject): TPaginatedView};
    {Building Block or Client reimplements this to install own flavor of paginated view}
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        NewPaginatedView := TPaginatedView.CREATE(object, SELF.Heap, SELF.view);
        {$IFC fTrace}EP;{$ENDC}
    END;


    FUNCTION  {TPrintManager.}PageWith{(VAR lPtInView: LPoint; VAR strip: Point): LONGINT};
        VAR pageBreak:  LONGINT;
            curStrip:   INTEGER;
            vhs:        VHSelect;
            finished:   BOOLEAN;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        LRectHaveLPt(SELF.view.extentLRect, lPtInView);
        FOR vhs := v TO h DO
            BEGIN
            finished := FALSE;
            curStrip := 1;
            WHILE (curStrip <= SELF.breaks[orthogonal[vhs]].size) AND NOT finished DO
                BEGIN
                pageBreak := TpLONGINT(SELF.breaks[orthogonal[vhs]].At(curStrip))^;
                IF lPtInView.vh[vhs] <= ABS(pageBreak) THEN
                    BEGIN
                    strip.vh[orthogonal[vhs]] := curStrip;
                    finished := TRUE;
                    END
                ELSE
                    curStrip := curStrip + 1;
                END;
            END;
            PageWith := (strip.vh[SELF.pageRiseDirection] - 1) *
                                      SELF.breaks[orthogonal[SELF.pageRiseDirection]].size
                        * strip.vh[orthogonal[SELF.pageRiseDirection]];
        {$IFC fTrace}EP;{$ENDC}
    END;


 {Note:	 The Pepsi and the Spring versions of the following procedure are completely different}

{$IFC libraryVersion <= 20}	   { P E P S I }
    {$S SgABCpri}
    PROCEDURE {TPrintManager.}Print{(printPref: TPrReserve)};
        LABEL 1,2,3,4,5,6;  {as demanded by Print Manager}
        VAR scaleOne:	    TScaler;
            pageNumber:	    LONGINT;
            rBand:	    Rect;
            pgsTotal:	    LONGINT;
            printerMetrics: TPrinterMetrics;
            error:	    INTEGER;
            dispatchCode:   INTEGER;  {dispatch code from LisaPrint}
            fSpool:	    BOOLEAN;
            prPrfAlias:	    TPrPrfAlias;
        BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
            prPrfAlias.reserve := printPref;
            printerMetrics :=  SELF.printerMetrics;
            SetPt(ScaleOne.numerator, 1, 1);
            SetPt(ScaleOne.denominator, 1, 1);
            pgsTotal := SELF.view.MaxPageToPrint; {by default, # of rowBreaks * # of colBreaks}
            fSpool := TRUE;
1:
            PrDocStart(dispatchCode, prPrfAlias.prIns, printLDSN);   {open the printer}

            CASE PrCheckErr(dispatchCode) OF
                PrGoDocStart:	 BEGIN
                                 fSpool := FALSE;
                                 GOTO 1;
                                 END;

                PrGoDocEnd:	 GOTO 5;
                PrGoExit:	 GOTO 6;
            END;  { case }

           theMarginPad.Rework
                (SELF.view, zeroPt, printerMetrics.res, 1,
                    scaleOne, printerPseudoPort);  {set up margin/body pads...}

           pageNumber := 0;

           REPEAT
               pageNumber := pageNumber + 1;

2:	       PrStartPage(dispatchCode);
               CASE PrCheckErr(dispatchCode) OF

                   prGoDocStart:    BEGIN
                                    fSpool := FALSE;
                                    GOTO 1;
                                    END;

                   prGoStartPage:   GOTO 2;

                   prGoEndPage:	    BEGIN
                                    SELF.SkipPage(pageNumber); {read on to start of next page, without
                                                                printing this one}
                                    GOTO 4;
                                    END;

                   prGoDocEnd:	    GOTO 5;
                   prGoExit:	    GOTO 6;

                   prGoCont:		     {actually print the page}
                       BEGIN
                       theMarginPad.SetForPage(pageNumber, zeroPt);
                       WHILE PrNextBand(rBand) DO
                           BEGIN
                           theMarginPad.ClipFurtherTo(rBand);
                           theMarginPad.Focus;
                           SELF.DrawPage;
3:			   PrDumpBand(dispatchCode);
                           CASE PrCheckErr(dispatchCode) OF
                               PrGoDocStart:
                                               BEGIN
                                               fSpool := FALSE;
                                               GOTO 1;
                                               END;

                               PrGoStartPage:  ABCBreak('PrGoStartPage received; page #=', pageNumber);
                               PrGoDumpBand :  GOTO 3;
                               PrGoEndPage  :  GOTO 4;
                               PrGoDocEnd   :  GOTO 5;
                               PrGoExit	    :  GOTO 6;
                               END; { CASE }
                           END;	   {WHILE PrNextBand}
                       END; {prGoCont dispatch code from prStartPage}
              END; {case on Err from StartPage}

4:	      PrEndPage(dispatchCode);
              CASE PrCheckErr(dispatchCode) OF
                 PrGoDocStart:  BEGIN
                                fSpool := FALSE;
                                GOTO 1;
                                END;

                 PrGoExit:      GOTO 2;
              END; { case }

        UNTIL pageNumber = pgsTotal;

5:	   PrDocEnd(dispatchCode);
           CASE PrCheckErr(dispatchCode) OF

               PrGoDocStart:  BEGIN
                              fSpool := FALSE;
                              GOTO 1;
                              END;

               PrGoStartPage:  ABCBreak('PrGoStartPage received; page #=', pageNumber);

               PrGoDocEnd   :  GOTO 5;
               PrGoExit	    :  GOTO 6;
           END; { case }

6:
        {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}	 { END of Pepsi-release version of TPrintmanager.Print }

(*********************************************************************************************************)

{$ELSEC}      {spring-release version of TPrintManager.Print follows}
    {$S SgABCpri}
    PROCEDURE {TPrintManager.}Print{(printPref: TPrReserve)};
        VAR unzoomed:	    TScaler;
            pageNumber:	    LONGINT;
            pgsTotal:	    LONGINT;
            prPort:	    TPrPort;
            prPrfAlias:	    TPrPrfAlias;
            resPageEnd:	    BOOLEAN;
     BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        prPrfAlias.reserve := printPref;
        SetPt(unzoomed.numerator, 1, 1);
        SetPt(unzoomed.denominator, 1, 1);
        pgsTotal := SELF.view.MaxPageToPrint; {by default, # of rowBreaks * # of colBreaks}

{$IFC LibraryVersion < 30}
        prPrfAlias.prPrf.prLdsn := printLDSN;
        IF PrDocStart(prPrfAlias.prPrf, prPort {, printLDSN} ) THEN  {open the printer}	      {++}
            {NB ldsn param not currently in spring interface, but Eric Z says it's going back in}
{$ELSEC}
        IF PrDocStart(prPrfAlias.prPrf, prPort , printLDSN, TRUE) THEN  {open the printer}	 {++}
{$ENDC}
            BEGIN
            theMarginPad.Rework
                 (SELF.view, zeroPt, SELF.printerMetrics.res, 1,
                     unzoomed, printerPseudoPort);  {set up margin/body pads...}
            RectRgn(altVisRgn, hugeRect);
            useAltVisRgn := TRUE;

            pageNumber := 0;

            REPEAT
                pageNumber := pageNumber + 1;

                IF NOT PrPageStart(prPrfAlias.prPrf, prPort) THEN {+SW+}
                    SELF.SkipPage(pageNumber)  {read on to start of next page, without printing this one}
                ELSE
                    BEGIN
                    theMarginPad.SetForPage(pageNumber, zeroPt);
                    theMarginPad.Focus;
                    SELF.DrawPage;
                    END;
                resPageEnd := PrPageEnd(prPrfAlias.prPrf, prPort);
            UNTIL
                resPageEnd OR (pageNumber >= pgsTotal);

            PrDocEnd(prPrfAlias.prPrf, prPort);
            {??? Do we need to stuff the prRec back into the doc?? Must ask Bayles}

            useAltVisRgn := FALSE;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
{$S SgABCres}
{$ENDC}	 {End of Spring-Release version of TPrintManager.Print}


    {$S sCldInit}
    PROCEDURE {TPrintManager.}ReactToPrinterChange;	 {several changes}
        VAR newExtent:	    LRect;
            minViewLRect:   LRect;
            s:		    TListScanner;
            pageBreak:	    LONGINT;
            vhs:	    VHSelect;
            curLPt:	    LPoint;
            pageIncrement:  LONGINT;
            metrics:	    TPrinterMetrics;

        PROCEDURE ScaleToViewedSpace(printRect: Rect; VAR viewedLRect: LRect);
            BEGIN
                SetLRect(viewedLRect,
                  LIntOvrInt(ORD4(printRect.left)   * SELF.view.res.h, metrics.res.h),
                  LIntOvrInt(ORD4(printRect.top)    * SELF.view.res.v, metrics.res.v),
                  LIntOvrInt(ORD4(printRect.right)  * SELF.view.res.h, metrics.res.h),
                  LIntOvrInt(ORD4(printRect.bottom) * SELF.view.res.v, metrics.res.v));
            END;

     BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
         { SELF.InvalidatePageBreaks, or some such ???}
         SELF.view.panel.window.GetPrinterMetrics;  {except maybe for view in first Panel created, this will
                                                     be an unnecessary (but inexpensive) step}
         metrics := SELF.view.panel.window.printerMetrics;
         SELF.printerMetrics := metrics;

         WITH SELF, printerMetrics DO
             BEGIN
 {$H-}	     ScaleToViewedSpace(paperRect,  paperLRect);
             ScaleToViewedSpace(printRect, printableLRect);
             END;
        LRectPlusLRect(SELF.paperLRect, SELF.pageMargins, SELF.contentLRect); {$H+}

        SELF.pageView.Resize(SELF.paperLRect);
        SELF.view.SetMinViewSize(newExtent);  {++}
        SELF.view.Resize(newExtent);	       {set view back to its min size}
        SELF.RedoBreaks;		    {may resize the view upwards again by a bit}
       {SELF.InvalidatePageBreaks again -- to force update where new breaks are to be shown}
     {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S sCldInit}
    PROCEDURE {TPrintManager.}RedoBreaks;
         VAR vhs:		    VHSelect;
             maxViewPixelsPerPage:  INTEGER;
             curLocation:	    LONGINT;
             onePixelTooMuch:	    LONGINT;
             endOfView:		    LONGINT;
             s:			    TListScanner;
             nextPageBreak:	    LONGINT;
             breakIndex:	    INTEGER;
             penultimatePageBreak:  LONGINT;
             newViewExtent:	    LRect;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        newViewExtent := SELF.view.extentLRect;
        SELF.ClearPageBreaks(TRUE);  {clear out old automatic breaks}
        FOR vhs := v TO h DO
            BEGIN
            WITH SELF.contentLRect DO
                IF vhs = v THEN
                    maxViewPixelsPerPage := right - left
                ELSE
                    maxViewPixelsPerPage := bottom - top;

            endOfView := SELF.view.extentLRect.botRight.vh[orthogonal[vhs]];

            breakIndex := 1;
            curLocation := 0;
            WHILE curLocation < endOfView DO
                BEGIN
                nextPageBreak := TpLONGINT(SELF.breaks[vhs].At(breakIndex))^;
                onePixelTooMuch := Min(curLocation + MaxViewPixelsPerPage, endOfView);
                IF ABS(nextPageBreak) <= onePixelTooMuch THEN
                    curLocation := ABS(nextPageBreak)
                ELSE {no manual page break; impose an automatic one -- propose onePixelTooMuch}
                    BEGIN
                    curLocation := SELF.view.ForceBreakAt(vhs, curLocation, onePixelTooMuch);
                    SELF.breaks[vhs].InsAt(breakIndex, @curLocation);
                    END;
                breakIndex := breakIndex + 1;
                END;

            IF SELF.view.fitPagesPerfectly THEN	 {make minor adjustment upward}
                BEGIN
                IF (SELF.breaks[vhs].size > 1) THEN
                    penultimatePageBreak := TpLONGINT(SELF.breaks[vhs].At(SELF.breaks[vhs].size - 1))^
                ELSE
                    penultimatePageBreak := 0;
                newViewExtent.botRight.vh[orthogonal[vhs]] := ABS(penultimatePageBreak) +
                                                                maxViewPixelsPerPage;
                END;

            END; {for vhs := v to h}
        SELF.view.Resize(newViewExtent);
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCpri}
    PROCEDURE {TPrintManager.}SetBreak{(vhs: VHSelect; where: LONGINT; isAutomatic: BOOLEAN)};
         VAR s:		    TListScanner;
             break:	    LONGINT;	 {comment gone}
             prevBreakLoc:  LONGINT;
             breakIndex:    INTEGER;
             finished:	    BOOLEAN;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        prevBreakLoc := 0;
        breakIndex := 1;
        finished := FALSE;
        WHILE (breakIndex <= SELF.breaks[vhs].size) AND NOT finished DO
            BEGIN
            break := TpLONGINT(SELF.breaks[vhs].At(breakIndex))^;
            IF ABS(break) > where THEN
              {found where to insert!}
                BEGIN
                where := SELF.view.ForceBreakAt(vhs, prevBreakLoc, where);
                break := where;
                IF NOT isAutomatic THEN
                    break := - break;
                SELF.breaks[vhs].InsAt(breakIndex, @break);
                finished := TRUE;
                END
            ELSE
            IF ABS(break) = where THEN
               {replace an existing page break}
                BEGIN
                break := where;
                IF NOT isAutomatic THEN
                    break := - break;
                SELF.breaks[vhs].PutAt(breakIndex, @break);
                finished := TRUE;
                END
            ELSE
                prevBreakLoc := ABS(break);

            breakIndex := breakIndex + 1;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCcld}
    PROCEDURE  {TPrintManager.}SetDfltHeadings;	 {client redefines}
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;
    {$S SgABCres}


    {$S SgABCpri}
     PROCEDURE {TPrintManager.}SkipPage{(pageNumber: LONGINT)};	 {client may want to redefine}
     BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
     END;
    {$S SgABCres}


{$S SgABCini}
END;
{$S SgABCres}



METHODS OF THeading;


{$S SgABCini}
    FUNCTION  {THeading.}CREATE{(object: TObject; heap: THeap; itsPrintManager: TPrintManager;
          itsExtentLRect: LRect; itsPageAlignment: TPageAlignment; itsOffsetFromAlignment: LPoint): THeading};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := THeading(TImage.CREATE(object, heap, itsExtentLRect, itsPrintManager.pageView));

        WITH SELF DO
            BEGIN
            printManager := itsPrintManager;
            pageAlignment := itsPageAlignment;
            offsetFromAlignment := itsOffsetFromAlignment;
            oddOnly := FALSE;
            evenOnly := FALSE;
            minPage := 2;
            maxPage := MAXLINT;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {THeading.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        TImage.Fields(Field);
        Field('printManager: TPrintManager');
        Field('pageAlignment: Byte'); {enumerated type}
        Field('offsetFromAlignment: LPoint');
        Field('oddOnly: BOOLEAN');
        Field('evenOnly: BOOLEAN');
        Field('minPage: LONGINT');
        Field('maxPage: LONGINT');
        Field('');
    END;
    {$S SgABCcld}
    {$ENDC}


    PROCEDURE {THeading.}AdjustForPage{(pageNumber: LONGINT; editing: BOOLEAN)};
    {will be overridden in Subclass if meaningful}
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;


    PROCEDURE {THeading.}ChangePageAlignment{(newPageAlignment: TPageAlignment)};
        VAR newOffset:	    LPoint;
        FUNCTION Mid(anLRect: LRect; vhs: VHSelect): LONGINT;
            BEGIN
            Mid := (anLRect.topLeft.vh[vhs] + anLRect.botRight.vh[vhs]) DIV 2;
            END;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        IF SELF.pageAlignment <> newPageAlignment THEN
            BEGIN
            CASE newPageAlignment OF
                aTopLeft, aBottomLeft:
                    newOffset.h := SELF.extentLRect.left -  SELF.view.extentLRect.left;
                aTopCenter, aBottomCenter:
                    newOffset.h := Mid(SELF.extentLRect, h)  -  Mid(SELF.view.extentLRect, h);
                aTopRight, aBottomRight:
                    newOffset.h := SELF.extentLRect.right - SELF.view.extentLRect.right;
                END;
            CASE newPageAlignment OF
                aTopLeft, aTopCenter, aTopRight:
                    newOffset.v := SELF.extentLRect.top - SELF.view.extentLRect.top;
                aBottomLeft, aBottomCenter, aBottomRight:
                    newOffset.v := SELF.extentLRect.bottom - SELF.view.extentLRect.bottom;
                END;
            SELF.offsetFromAlignment := newOffset;
            SELF.pageAlignment := newPageAlignment;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    PROCEDURE {THeading.}Draw;  {will be overridden in Subclass if meaningful}
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        IF SELF.shouldFrame THEN
            FrameLRect(SELF.extentLRect);
        {$IFC fTrace}EP;{$ENDC}
    END;


    PROCEDURE {THeading.}LocateOnPage{(editing: BOOLEAN)};
    {called after client has adjusted the extentLRect and (possibly) the offsetFromAlignment}
        VAR currentH, currentV, targetH, targetV:   LONGINT;
            offset: LPoint;
            pmgr:   TPrintManager;	       (* CIRCUMVENT COMPILER BUG *)
        {NB: Someday someone could use vhs and other tricks to tighten this up}
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        WITH SELF DO
          BEGIN	        (* CIRCUMVENT COMPILER BUG *)
          pmgr := SELF.printManager;	     (* CIRCUMVENT COMPILER BUG *)
          WITH pmgr, paperLRect DO
            BEGIN
            CASE {SELF.}pageAlignment OF
                aTopLeft,
                  aBottomLeft:	    BEGIN
                                    currentH := {SELF.}extentLRect.left;
                                    targetH := {paperLRect.}left;
                                    END;
                aTopCenter,
                  aBottomCenter:    BEGIN
                                    currentH := (extentLRect.right + extentLRect.left) DIV 2;
                                    targetH := {paperLRect.}(right + left) DIV 2;
                                    END;
                aTopRight,
                  aBottomRight:	    BEGIN
                                    currentH := extentLRect.right;
                                    targetH :=  right;
                                    END;
                END;

            CASE {SELF.}pageAlignment OF
                aTopLeft,
                  aTopCenter,
                  aTopRight:	    BEGIN
                                    currentV := extentLRect.top;
                                    targetV := top;
                                    END;
                aBottomLeft,
                  aBottomCenter,
                  aBottomRight:	    BEGIN
                                    currentV := extentLRect.bottom;
                                    targetV := bottom;
                                    END;
                END;
            END;
          END;	       (* CIRCUMVENT COMPILER BUG *)

        WITH SELF.offsetFromAlignment DO
            {$H-}SetLPt(offset, targetH - currentH + h, targetV - currentV + v); {$H+}
        SELF.OffsetBy(offset);
        {$IFC fTrace}EP;{$ENDC}
    END;


    FUNCTION  {THeading.}ShouldDraw{(pageNumber: LONGINT): BOOLEAN};
        VAR judgment: BOOLEAN;
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        WITH SELF DO
            IF (oddOnly AND NOT ODD(pageNumber)) OR
               (evenOnly AND ODD(pageNumber))	 OR
               (pageNumber < minPage)		 OR
               (pageNumber > maxPage)	 THEN
                    judgment := FALSE
            ELSE
               judgment := TRUE;
        ShouldDraw := judgment;
        {$IFC fTrace}EP;{$ENDC}
    END;


    FUNCTION  {THeading.}ShouldFrame{: BOOLEAN};
    BEGIN
        {$IFC fTrace}BP(9);{$ENDC}
        ShouldFrame := NOT amPrinting;  {default}
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
END;
{$S SgABCres}



METHODS OF TSelection;

    {$S sStartup}
    FUNCTION  {TSelection.}CREATE{(object: TObject; heap: THeap; itsView: TView; itsKind: INTEGER;
                                itsAnchorLPt: LPoint): TSelection};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF object = NIL THEN
            object := NewObject(heap, THISCLASS);
        SELF := TSelection(object);

        WITH SELF DO
            BEGIN
            currLPt := itsAnchorLPt;
            anchorLPt := itsAnchorLPt;
            boundLRect := hugeLRect;
            kind := itsKind;
            view := itsView;
            panel := view.panel;
            IF panel <> NIL THEN
                window := panel.window;
            coSelection := NIL;
            canCrossPanels := FALSE;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION  {TSelection.}Clone{(heap: Theap): TObject};
    VAR selection:      TSelection;
        coSelection:    Tselection;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        selection := TSelection(SUPERSELF.Clone(heap));
        IF SELF.coSelection <> NIL THEN
            BEGIN
            coSelection := TSelection(SELF.coSelection.Clone(heap));
            selection.coSelection := coSelection;
            END;
        Clone := selection;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}Free;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        Free(SELF.coSelection);
        TObject.Free;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION  {TSelection.}FreedAndReplacedBy{(selection: TSelection): TSelection};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.Become(selection);
        FreedAndReplacedBy := SELF;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$IFC fDebugMethods}
    {$S SgABCdbg}
    PROCEDURE {TSelection.}Fields{(PROCEDURE Field(nameAndType: S255))};
    BEGIN
        Field('window: TWindow');
        Field('panel: TPanel');
        Field('view: TView');
        Field('kind: INTEGER');
        Field('anchorLPt: LPoint');
        Field('currLPt: LPoint');
        Field('boundLRect: LRect'); {+++LSR+++}
        Field('coSelection: TSelection');
        Field('canCrossPanels: BOOLEAN');
        Field('');
    END;
    {$S SgABCres}
    {$ENDC}


    {$S sRes}
    FUNCTION  {TSelection.}CanDoCommand{(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN};
    BEGIN
        {$IFC fTrace}BP(6);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            CanDoCommand := SELF.coSelection.CanDoCommand(cmdNumber, checkIt)
        ELSE
            CanDoCommand := SELF.window.CanDoCommand(cmdNumber, checkIt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sAlert}
    PROCEDURE {TSelection.}CantDoCmd{(cmdNumber: TCmdNumber)};
        VAR cmdStr: S255;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF menuBar.GetCmdName(cmdNumber, @cmdStr) THEN
            BEGIN
            process.ArgAlert(1, cmdStr);
            process.Stop(phUnkCmd);
            END
        ELSE
            SELF.CantDoIt;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sAlert}
    PROCEDURE {TSelection.}CantDoIt;
        VAR ph: INTEGER;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.kind = nothingKind THEN
            ph := phNoSel
        ELSE
            ph := phSelCant;
        process.Stop(ph);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}Deselect;
    VAR selection:  TSelection;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.panel.Highlight(SELF, hOnToOff);
        selection := SELF.FreedAndReplacedBy(SELF.view.NoSelection);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TSelection.}DrawGhost;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}DoKey{(ascii: CHAR; keycap: Byte; shiftKey, appleKey, optionKey: BOOLEAN)};
        VAR cmdNumber:	  TCmdNumber;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF appleKey THEN
            BEGIN
            SELF.window.SetupMenus;
            cmdNumber := menuBar.CmdKey(ascii);
            SELF.window.DoCommand(cmdNumber);
            END
        ELSE
        IF currentDocument = clipboard THEN
            process.Stop(phEditClip)
        ELSE
        IF SELF.kind = nothingKind THEN
            process.Stop(phNoSel)
        ELSE
            BEGIN
            CASE ORD(ascii) OF
                ascArwDown:
                    SELF.KeyEnter(0, 1);
                ascArwLeft:
                    SELF.KeyEnter(-1, 0);
                ascArwRight:
                    SELF.KeyEnter(1, 0);
                ascArwUp:
                    SELF.KeyEnter(0, -1);
                ascClear:
                    SELF.KeyClear;
                ascEnter:
                    SELF.KeyEnter(0, 0);
                OTHERWISE
                    CASE ORD(ascii) OF
                        ascBackspace:
                            IF shiftKey THEN
                                SELF.KeyForward(appleKey)
                            ELSE
                                SELF.KeyBack(appleKey);
                        ascReturn:
                            SELF.KeyReturn;
                        ascTab:
                            SELF.KeyTab(shiftKey);
                        OTHERWISE
                            SELF.KeyChar(ascii);
                        END;
                END;
            IF ORD(ascii) <> ascClear THEN
                process.RememberCommand(uKeyDown); {clear is special}
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}GetHysteresis{(VAR hysterPt: Point)};
    BEGIN
        {$IFC fTrace}BP(3);{$ENDC}
        SetPt(hysterPt, stdHHysteresis, stdVHysteresis);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCpri}
    PROCEDURE {TSelection.}HaveView{(view: TView)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        SELF.view := view;
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.HaveView(view);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sStartup}
    PROCEDURE {TSelection.}Highlight{(highTransit: THighTransit)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.Highlight(highTransit);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}IdleBegin{(centiSeconds: LONGINT)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.IdleBegin(centiSeconds)
        ELSE
            SELF.window.IdleBegin(centiSeconds);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}IdleContinue{(centiSeconds: LONGINT)};
    BEGIN
        {$IFC fTrace}BP(5);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.IdleContinue(centiSeconds)
        ELSE
            SELF.window.IdleContinue(centiSeconds);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}IdleEnd{(centiSeconds: LONGINT)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.IdleEnd(centiSeconds)
        ELSE
            SELF.window.IdleEnd(centiSeconds);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}KeyBack{(fWord: BOOLEAN)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.KeyBack(fWord)
        ELSE
            SELF.CantDoCmd(uBackspace);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}KeyChar{(ch: CHAR)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.KeyChar(ch)
        ELSE
            SELF.CantDoCmd(uTyping);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}KeyClear;
        VAR dummy:  BOOLEAN;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.KeyClear
        ELSE IF (menubar.GetCmdName(uClear, NIL))   {there is a CLEAR menu item} AND
                (SELF.CanDoCommand(uClear, dummy))  {the selection says it can do it} THEN
            BEGIN				    {make believe the user chose the menu item}
            menuBar.HighlightMenu(uClear);
            SELF.window.DoCommand(uClear);
            END
        ELSE
            BEGIN
            SELF.CantDoCmd(uClear);
            process.RememberCommand(uClear);
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}KeyEnter{(dh, dv: INTEGER)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.KeyEnter(dh, dv)
        ELSE
            SELF.CantDoCmd(uEnter);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}KeyForward{(fWord: BOOLEAN)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.KeyForward(fWord)
        ELSE
            SELF.CantDoCmd(uForwardSpace);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}KeyPause;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.KeyPause;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}KeyReturn;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.KeyReturn
        ELSE
            SELF.CantDoCmd(uReturn);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}KeyTab{(fBackward: BOOLEAN)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.KeyTab(fBackward)
        ELSE
            SELF.CantDoCmd(uTab);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCres}
    PROCEDURE {TSelection.}MarkChanged;
        VAR delta:      INTEGER;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.panel.window = currentWindow THEN
            BEGIN
            IF currentWindow.lastCmd = NIL THEN
                delta := 1
            ELSE
            IF currentWindow.lastCmd.doing THEN
                delta := 1
            ELSE
                delta := -1;

            currentWindow.changes := currentWindow.changes + delta;
            IF boundDocument = currentDocument THEN
                WITH boundDocument DO
                    dataSegment.changes := dataSegment.changes + delta;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}MousePress{(mouseLPt: LPoint)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.MousePress(mouseLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}MouseMove{(mouseLPt: LPoint)};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.MouseMove(mouseLPt);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}MouseRelease;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.MouseRelease;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S SgABCcld}
    PROCEDURE {TSelection.}MoveBackToAnchor;	    {dest panel of cross-panel drag refused DoReceive}
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    FUNCTION  {TSelection.}NewCommand{(cmdNumber: TCmdNumber): TCommand};
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            NewCommand := SELF.coSelection.NewCommand(cmdNumber)
        ELSE
            NewCommand := SELF.window.NewCommand(cmdNumber);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}PerformCommand{(command: TCommand; cmdPhase: TCmdPhase)};{+sw+}
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        command.doing := (cmdPhase <> undoPhase);
        command.Perform(cmdPhase);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}Restore;     {SELF should be undoSelection}
        VAR selection:  TSelection;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        selection := SELF.panel.selection.FreedAndReplacedBy(
                                            TSelection(SELF.panel.undoSelection.Clone(SELF.Heap))); {$}
        selection := SELF.panel.undoSelection.FreedAndReplaceBy(SELF.view.NoSelection);
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}Reveal(asMuchAsPossible: BOOLEAN);
        TYPE TXLRect = PACKED ARRAY [1..SIZEOF(LRect)] OF CHAR;
        VAR lr:	        LRect;
            hMin:       INTEGER;
            vMin:       INTEGER;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.Reveal(asMuchAsPossible)
        ELSE
            BEGIN
            lr := SELF.boundLRect;
            IF TXLRect(lr) <> TXLRect(hugeLRect) THEN
                BEGIN
                IF NOT asMuchAsPossible THEN
                    BEGIN
                    hMin := 30;
                    vMin := 20;
                    END
                ELSE
                    WITH lr DO
                        BEGIN
                        hMin := Min(MAXINT, right - left + 6);
                        vMin := Min(MAXINT, bottom - top + 4);
                        END;
                SELF.panel.RevealLRect(lr, hMin, vMin);
                END;
            END;
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}Save;
        VAR selection:  TSelection;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        selection := SELF.panel.undoSelection.FreedAndReplacedBy(TSelection(SELF.Clone(SELF.Heap)));
        {$IFC fTrace}EP;{$ENDC}
    END;


    {$S sRes}
    PROCEDURE {TSelection.}SelectParagraphs;
    BEGIN
        {$IFC fTrace}BP(7);{$ENDC}
        IF SELF.coSelection <> NIL THEN
            SELF.coSelection.SelectParagraphs;
        {$IFC fTrace}EP;{$ENDC}
    END;


{$S SgABCini}
BEGIN
    cSelection := THISCLASS;
END;
{$S SgABCres}











